import type { FC, ReactNode } from 'react'
import React, { memo, useEffect, useState } from 'react'
import { Button, FormInstance, Input, message, Switch, Tag } from 'antd'
import dayjs from 'dayjs'
import PageSearch from '@/components/page-search'
import PageContent from '@/components/page-content'
import PageModal from '@/components/page-modal'
import VerifyCodeButton from '@/components/verify-code-button'
import UploadImg from '@/components/upload-img'
import UploadExcel from '@/components/upload-excel'
import usePageSearch from '@/hooks/use-page-search'
import usePageModal from '@/hooks/use-page-modal'
import usePageContent from '@/hooks/use-page-content'
import userListSearch from './config/userlist-search'
import userListContent from './config/userlist-content'
import userListModalBanned from './config/userlist-modal-banned'
import getUserListModalAddOrEdit from './config/userlist-modal-add-or-edit'
import getUserListModalAssignRole from './config/userlist-modal-assign-role'
import { fetchSelectRoleListAction } from '@/store/module/main/role-list'
import {
  fetchPageAddOrEditAction,
  fetchPageBatchDeleteAction,
  fetchPageDeleteAction,
  fetchPageListAction
} from '@/store/module/main/page-common'
import {
  getExcelTemplate,
  getExportedExcel,
  reqAssignRole,
  reqBanned,
  reqBatchBanned,
  reqBatchUntieDisable,
  reqKickOut,
  reqResetUserPwd,
  reqUntieDisable
} from '@/service/module/main/system/user-list'
import downloadFile from '@/utils/download'
import { encryptData } from '@/utils/encrypt'
import confirmModal from '@/utils/confirm-modal'
import { ActionDesc } from '@/global/constant'
import { BaseInfoWrapper } from './style'

interface IProps {
  children?: ReactNode
}

const inputWithVerifyCodeStyle = {
  display: 'flex',
  alignItems: 'center'
}
const UserList: FC<IProps> = (props) => {
  // 定义一个名为 headPortrait 的状态和用于更新该状态的函数 setHeadPortrait
  const [headPortrait, setHeadPortrait] = useState('')

  // 用于设置 headPortrait 状态的函数
  function getFileUrl(url: string) {
    setHeadPortrait(url)
  }

  // 使用 usePageSearch 和 usePageModal 自定义 Hook 并提取返回值
  const { pageContentRef, searchClick, resetClick } = usePageSearch()
  const { pageModalRef, onModalOk, onModalCancel, getCodeClick } = usePageModal(
    {
      okCb,
      afterCloseResetStatusCb,
      cancelCb
    }
  )
  // 使用 usePageContent 自定义 Hook 并提取返回值和函数
  const {
    store: { propIds, searchParams, publicKey },
    modal: [curModalConfig, setCurModalConfig],
    record: [currentRecord, setCurrentRecord],
    batchBanned: [isBatchBanned, setIsBatchBanned],
    dispatch,
    toSecondAuth,
    handleJudgeChecked,
    handleSecondAuth
  } = usePageContent({ pageModalRef })

  // 用于重置模态框状态的回调函数
  function afterCloseResetStatusCb() {
    // ！！！这一步非常关键，我们希望每次点击确认后要销毁这个modal框的状态，
    // 但是只有modal的配置发生改变才会重新渲染这个modal组件
    // 假如我们两次点击二次认证框，但是我们希望下一次进去消除上一次残留的状态，就要让他的配置发生改变，所以这里改为空
    // setCurModalConfig({})
    setCurModalConfig({})
  }

  // 用于处理模态框的取消事件的回调函数
  function cancelCb() {
    setHeadPortrait('')
    setCurModalConfig({})
  }

  /**
   * 根据当前模态框配置处理表单提交。
   * @param form - 包含表单数据的 Ant Design `FormInstance` 对象。
   */
  async function okCb(form: FormInstance | undefined) {
    // 从当前模态框配置中提取操作描述
    const { desc } = curModalConfig.formProps

    // 使用 Ant Design 的 `getFieldsValue` 方法检索表单值
    const values = form?.getFieldsValue()

    // 使用 switch 语句处理不同的操作描述
    switch (desc) {
      // 如果操作为“SecondAuth”，则调用 `toSecondAuth` 函数
      case ActionDesc.SecondAuth:
        return toSecondAuth(values)

      // 如果操作为“UserBanned”，则调用 `userToBanned` 函数并传入 `isBatchBanned` 标志
      case ActionDesc.UserBanned:
        return await userToBanned(values, isBatchBanned)

      // 如果操作为“Add”或“Edit”，则调用 `userToAddOrEdit` 函数并传入适当的标志
      case ActionDesc.Add:
      case ActionDesc.Edit:
        return await userToAddOrEdit(values, desc === ActionDesc.Add)

      // 如果操作为“UserAssignRole”，则调用 `userToAssignRole` 函数
      case ActionDesc.UserAssignRole:
        return await userToAssignRole(values)

      // 如果操作不匹配任何已知描述，则抛出错误
      default:
        throw new Error(`未知的操作描述：${desc}`)
    }
  }

  // 通用：处理“编辑”的回显数据的，只要config一改变，就手动设置初始值
  useEffect(() => {
    if (curModalConfig?.formProps?.desc === ActionDesc.Edit) {
      const {
        street,
        county,
        city,
        province,
        detailAddress,
        email,
        headPortrait,
        identityCard,
        nickName,
        sex,
        status,
        userName,
        userPhone,
        userType
      } = currentRecord
      // 整理表单参数
      const address = [province, city, county, street]
      const form = pageModalRef.current?.getFormInstance()
      form?.setFieldsValue({
        address,
        detailAddress,
        email,
        headPortrait,
        identityCard,
        nickName,
        sex,
        status,
        userName,
        userPhone,
        userType
      })
      setHeadPortrait(headPortrait)
    }
  }, [curModalConfig])

  /**
   * 通用的按钮操作函数.
   * @param key - 操作类型。
   * @param record - 当前行数据。
   */
  async function actionClick(key: any, record?: any) {
    // 设置当前行数据：如果是批量操作和新增就没有record也要设置，表明是空状态
    // 这样做可以避免，先点修改再点增加，要把修改后残留的id去掉，否则新增也会带上id
    setCurrentRecord(record)
    // 操作类型
    if (key === ActionDesc.Add) {
      // 用户新增
      const config = getUserListModalAddOrEdit(true)
      setCurModalConfig(config)
      pageModalRef.current?.openModal()
    } else if (key === ActionDesc.Edit) {
      // 用户修改
      const config = getUserListModalAddOrEdit(false)
      setCurModalConfig(config)
      pageModalRef.current?.openModal()
    } else if (key === ActionDesc.Delete) {
      // 单删除
      handleSecondAuth(() => {
        confirmModal('是否删除该用户?').then(() =>
          dispatch(fetchPageDeleteAction(record.userId))
        )
      })
    } else if (key === ActionDesc.BatchDelete) {
      // 批量删除
      handleJudgeChecked(() =>
        handleSecondAuth(() => {
          confirmModal('是否删除选中的用户?').then(() =>
            dispatch(fetchPageBatchDeleteAction(propIds))
          )
        })
      )
    } else if (key === ActionDesc.UserBatchBanned) {
      // 批量封号
      handleJudgeChecked(() =>
        handleSecondAuth(() => {
          // 传入配置并打开
          setIsBatchBanned(true)
          setCurModalConfig(userListModalBanned)
          pageModalRef.current?.openModal()
        })
      )
    } else if (key === ActionDesc.UserBatchUniteDisable) {
      // 批量解封
      handleJudgeChecked(() => {
        handleSecondAuth(async () => {
          const data = { ids: propIds }
          const encryptStr = encryptData(publicKey, data)
          await reqBatchUntieDisable(encryptStr)
          await dispatch(fetchPageListAction(searchParams))
        })
      })
    } else if (key === ActionDesc.UserResetPwd) {
      // 重置密码
      handleSecondAuth(() => {
        confirmModal('是否重置密码').then(() => reqResetUserPwd(record.userId))
      })
    } else if (key === ActionDesc.UserKickOut) {
      // 强制下线
      handleSecondAuth(() => {
        confirmModal('是否强制该用户下线').then(() => reqKickOut(record.userId))
      })
    } else if (key === ActionDesc.UserAssignRole) {
      // 分配角色
      // 1.先获取角色数据
      const { payload } = await dispatch(fetchSelectRoleListAction())
      // 2.将角色数据传入配置项
      const config = getUserListModalAssignRole(payload)
      // 3.打开modal框
      setCurModalConfig(config)
      pageModalRef.current?.openModal()
    }
  }

  // 封号与解禁
  function handleUserBanned(checked: boolean, record: any) {
    handleSecondAuth(async () => {
      // 获取当前行数据
      setCurrentRecord(record)
      // 点击后开启，也就是原来是封号，准备去解封
      if (checked) {
        await reqUntieDisable(record.userId)
        // 请求成功重新请求列表数据
        dispatch(fetchPageListAction(searchParams))
      } else {
        // 传入配置并打开
        setIsBatchBanned(false)
        setCurModalConfig(userListModalBanned)
        pageModalRef.current?.openModal()
      }
    })
  }

  // 封号的具体逻辑
  async function userToBanned(values: any, isBatch = false) {
    const { type, bannedCause, time } = values
    // 批量封号的默认配置
    const batchOriginParams = { bannedCause, bannedTime: -1, ids: propIds }
    // 单个封号的默认配置
    const originParams = {
      bannedCause,
      bannedTime: -1,
      userId: currentRecord.userId
    }
    const params = isBatch ? batchOriginParams : originParams
    // 假如是限时封号,对配置修改一下
    if (type === 0) {
      const curTimestamp = dayjs().valueOf() / 1000
      const targetTimestamp = dayjs(time).unix() // 这个直接就已经是/1000的格式了
      const seconds = targetTimestamp - curTimestamp
      console.log(curTimestamp, targetTimestamp)
      if (seconds <= 0) {
        message.error('目标时间错误,请选择未来的时间')
        return false
      } else {
        params.bannedTime = seconds
      }
    }
    // 对参数据加密再发请求
    const encryptStr = encryptData(publicKey, params)
    if (encryptStr) {
      // 批量封号
      isBatch && (await reqBatchBanned(encryptStr))
      // 单个封号
      !isBatch && (await reqBanned(encryptStr))
    }
    // 请求成功重新请求列表数据
    dispatch(fetchPageListAction(searchParams))
    return true
  }
  // 新增或者修改， 参数2：true -> 新增
  async function userToAddOrEdit(values: any, isAdd: boolean) {
    const { address, headPortrait: a, ...otherParams } = values
    const [province, city, county, street] = address
    const newParams = {
      ...otherParams,
      headPortrait,
      province,
      city,
      county,
      street,
      ...(currentRecord?.userId !== undefined && {
        userId: currentRecord.userId,
        addressId: currentRecord.addressId
      })
    }

    return dispatch(fetchPageAddOrEditAction({ params: newParams, isAdd }))
  }

  // 分配角色
  async function userToAssignRole(values: any) {
    const { roleId } = values
    const params = { roleId, userId: currentRecord.userId }
    const encryptStr = encryptData(publicKey, params)
    if (encryptStr) {
      await reqAssignRole(encryptStr)
      // 请求成功重新请求列表数据
      dispatch(fetchPageListAction(searchParams))
      return true
    }
  }

  // 导出Excel
  async function exportExcel() {
    const res = await getExportedExcel()
    downloadFile(res, 'user.xlsx')
  }

  // 下载模板
  async function downloadTemplate() {
    // res为blob流
    const res = await getExcelTemplate()
    // 下载功能
    downloadFile(res, 'template.xlsx')
  }

  // 通用：自定义表格内容--渲染自定义的表单项
  function renderTableCpn(
    text: string | number,
    record: any,
    customkey: string
  ) {
    const {
      province,
      city,
      county,
      street,
      detailAddress,
      headPortrait,
      userName,
      nickName,
      userPhone,
      email,
      identityCard,
      sex
    } = record
    if (customkey === 'baseInfo') {
      return (
        <BaseInfoWrapper>
          <div className="left">
            <img src={headPortrait} className="headPortrait" alt="" />
            <Tag
              color={sex === 0 ? 'error' : sex === 1 ? 'processing' : 'success'}
            >
              {sex === 0 ? '女' : sex === 1 ? '男' : '未知'}
            </Tag>
          </div>
          <div className="right">
            <div>用户名：{userName}</div>
            <div>昵称：{nickName}</div>
            <div>手机号：{userPhone}</div>
            <div>邮件：{email}</div>
            <div>身份证：{identityCard}</div>
            <div>
              地址：{`${province}${city}${county}${street}${detailAddress}`}
            </div>
          </div>
        </BaseInfoWrapper>
      )
    } else if (customkey === 'userType') {
      return (
        <Tag color={text ? 'success' : 'processing'}>
          {text ? '用户' : '管理员'}
        </Tag>
      )
    } else if (customkey === 'status') {
      return (
        <Switch
          checked={!!text}
          checkedChildren="正常"
          unCheckedChildren="封禁"
          onClick={(checked) => handleUserBanned(checked, record)}
        />
      )
    } else if (customkey === 'roleName') {
      return <Tag>{text}</Tag>
    } else return <span>{text}</span>
  }

  const headerRightEl = (
    <div className="excel-action">
      <UploadExcel />
      <Button style={{ margin: '0 10px' }} size="small" onClick={exportExcel}>
        导出
      </Button>
      <Button size="small" onClick={downloadTemplate}>
        下载模板
      </Button>
    </div>
  )

  return (
    <>
      <PageSearch
        config={userListSearch}
        searchClick={searchClick}
        resetClick={resetClick}
      ></PageSearch>
      <PageContent
        ref={pageContentRef}
        config={userListContent}
        actionClick={actionClick}
        headerRightArea={headerRightEl}
      >
        {renderTableCpn}
      </PageContent>
      <PageModal
        ref={pageModalRef}
        modalConfig={curModalConfig}
        onOk={onModalOk}
        onCancel={onModalCancel}
      >
        <div key="code" style={inputWithVerifyCodeStyle}>
          <Input name="code" />
          <VerifyCodeButton onClick={getCodeClick} />
        </div>
        <UploadImg
          key="headPortrait"
          imgUrl={headPortrait}
          getFileUrl={getFileUrl}
        />
      </PageModal>
    </>
  )
}

export default memo(UserList)
